// Copyright 2023 Srhino Co., Ltd. All rights reserved.

package log

import (
	"os"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

type wrappedLogger struct {
	zapLogger     *zap.Logger
	sugaredLogger *zap.SugaredLogger

	opts *loggerOptions
}

func NewLogger(opt ...LoggerOption) Logger {
	var opts loggerOptions
	for _, o := range opt {
		o.apply(&opts)
	}
	(&opts).setDefault()

	var l = &wrappedLogger{opts: &opts}
	l.zapLogger = l.buildZapLogger()
	l.sugaredLogger = l.zapLogger.Sugar()
	return l
}

func NewWrappedLogger(opt ...LoggerOption) WrappedLogger {
	var opts loggerOptions
	for _, o := range opt {
		o.apply(&opts)
	}
	(&opts).setDefault()

	var l = &wrappedLogger{opts: &opts}
	l.zapLogger = l.buildZapLogger()
	l.sugaredLogger = l.zapLogger.Sugar()
	return l
}

func (l *wrappedLogger) buildZapLogger() *zap.Logger {
	config := zap.NewProductionConfig()
	config.Level = zap.NewAtomicLevelAt(l.zapLevel())
	config.EncoderConfig.EncodeTime = ISO8601TimeEncoderForShanghaiLocalization
	jsonEncoder := zapcore.NewJSONEncoder(config.EncoderConfig)
	ws := zapcore.AddSync(&lumberjack.Logger{
		Filename:   l.opts.fileName,
		MaxSize:    l.opts.maxSize, // MB
		MaxBackups: l.opts.maxBackups,
		MaxAge:     l.opts.maxAge, // Days
		Compress:   l.opts.compress,
		LocalTime:  true,
	})

	var cores []zapcore.Core
	cores = append(cores, zapcore.NewCore(jsonEncoder, ws, config.Level))

	// lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
	// 	return lvl < zapcore.ErrorLevel
	// })
	// cores = append(cores, zapcore.NewCore(jsonEncoder, zapcore.Lock(os.Stdout), lowPriority))

	if l.opts.stdOut {
		cores = append(cores, zapcore.NewCore(jsonEncoder, zapcore.Lock(os.Stdout), config.Level))
	}
	// else { // 默认输出错误级及其以上日志
	// 	highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
	// 		return lvl >= zapcore.ErrorLevel
	// 	})
	// 	cores = append(cores, zapcore.NewCore(jsonEncoder, zapcore.Lock(os.Stderr), highPriority))
	// }

	return zap.New(zapcore.NewTee(cores...), zap.AddCaller(), zap.AddStacktrace(zap.ErrorLevel))
}

func (l *wrappedLogger) zapLevel() zapcore.Level {
	switch l.opts.level {
	case "debug", "DEBUG":
		return zap.DebugLevel
	case "info", "INFO":
		return zap.InfoLevel
	case "warn", "WARN":
		return zap.WarnLevel
	case "error", "ERROR":
		return zap.ErrorLevel
	case "panic", "PANIC":
		return zap.PanicLevel
	case "fatal", "FATAL":
		return zap.FatalLevel
	default:
		return zap.InfoLevel
	}
}
